<?php

class FormBuilder_Element
{
	// Most elements will use this structure.
	protected $elm   = array ( 'name', 'value', 'attributes' );
	protected $label = null;

	public function __construct ($name = null, $value = null, $attributes = null)
	{
		$this->elm = array_fill_keys($this->elm, null);

		$this->setName($name);
		$this->setValue($value);
		$this->setAttributes($attributes);
	}

#------------------------------------------------------------------------------

	/**
	 * Magic __call method. Using it to reduce all the get interface as
	 * they just return a few paramerters. Also accepts render as a method.
	 *
	 * @param string $func	Function name.
	 * @param array  $args	Array of arguments like that of func_get_args().
	 * 
	 * @return mixed
	 */
	public function __call ($func, $args)
	{
		$func = defvalue(strtolower($func));

		if ($func) {
			if ($func === 'render') {
				return $this->__toString();
			}
			
			if (substr($func, 0, 3) === 'get') {
				$func = strpos($func, 3);
				if (isset($this->elm[$func])) {
					return $this->elm[$func];
				}
			}
		}

		return false;
	}

#------------------------------------------------------------------------------

	public function setName ($name = null)
	{
		$name = defvalue($name);

		// If $name is null we will create a random name.
		if ($name === false) {
			$name = mt_rand() + microtime();
			$name = base64_encode($name);
			$name = str_shuffle($name);
			$name = trim($name, '=');
		}

		if ($this->elm['name'] !== $name && FormBuilder_Children::exists($name)) {
			$error = 'Name already in use.';

			throw new FormBuilder_Exception($error, 555);
			return false;
		}

		if (!preg_match('/^[a-zA-z][a-zA-Z0-9_\-\][:.=]+/', $name)) {
			$error = 'Name must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").';

			throw new FormBuilder_Exception($error, 209);
			return false;
		}

		$this->_update($name);
		$this->elm['name'] = $name;

		return $this;
	}

	public function setValue ($value = null)
	{
	    $value = defvalue($value, null);
	    $this->elm['value'] = htmlentities($value, ENT_QUOTES, 'UTF-8');
	    return $this;
	}


	protected function addAttribute ($attr, $value)
	{
		$attr  = strtolower(trim($attr));
		$value = htmlentities($value, ENT_QUOTES, 'UTF-8');

		if (!preg_match('/^[a-z][a-z\-:.]+$/', $attr)) {
			$error = 'Attribute names must begain with a letter ([a-z]) and may be followed by any number of letters, hyphens ("-"), colons(":"), and periods (".").';

			throw new FormBuilder_Exception($error, 209);
			return false;
		}

		$this->elm['attributes'][$attr] = $value;
	}

	public function setAttributes ()
	{
		$num  = func_num_args();
		$args = func_get_args();

		if ($num == 0 || is_null($args[0])) {
			return $this;
		}

		if ($num == 1 && is_array($args[0])) {
			$k = array_keys($args[0]); $v = array_values($args[0]);
			array_map( array($this, 'addAttribute'), $k, $v );
			return $this;
		}

		foreach (array_chunk($args, 2) as $arg) {
			$this->addAttribute($arg[0], $arg[1]);
		}

		return $this;
	}


	public function setAttribute ($attr, $value)
	{
		$this->addAttribute($attr, $value);
		return $this;
	}

	public function getAttribute ($attr)
	{
		$attr = defvalue(strtolower($attr));
		if ($attr && isset($this->elm['attributes'][$attr])) {
			return $this->elm['attributes'][$attr];
		}

		return false;
	}

#------------------------------------------------------------------------------

	private function _update ($name)
	{
		// Child Registry
		( FormBuilder_Children::exists($this->elm['name']) )
			? FormBuilder_Children::update($this->elm['name'], $name)
			: FormBuilder_Children::add($name, $this);

		// Label
		if ($this->label !== null) {
			$this->label->setName($name);
		}

		// Id
		$id = $this->getAttribute('id');
		if ($id === false || empty($id) || $id == $this->elm['name']) {
			$this->setAttribute('id', $name);
		}
	}

#------------------------------------------------------------------------------

	public function addLabel ($text = null, $position = FormBuilder_Element_Label::FRONT)
	{
		$this->label = new FormBuilder_Element_Label($this->elm['name'], $text, $position);
		return $this->label;
	}

	public function labelText ($text)
	{
		return $this->label->setValue($text);
	}

	public function labelPosition ($position = FormBuilder_Element_Label::FRONT)
	{
		return $this->label->setPosition($position);
	}

	public function labelAttributes()
	{
		$args = func_get_args();
		return call_user_func_array(array($this->label, 'setAttributes'), $args);
	}
}

